/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2023-2024.
 * Description: rtos kbox modification for printk.c
 * Author: Wang Haitao
 * Create: 2023-8-31
 */

#include <internal/kbox_printk.h>
#include <linux/printk.h>
#include <linux/set_kbox_region.h>
#include <linux/percpu-defs.h>
#ifdef CONFIG_RTOS_PPC_DYING_INT
#include <asm/rtos_dying_int.h>
#include <internal/rtos_dying.h>
#endif
#ifdef CONFIG_FIQ_GLUE
#include <linux/hal/fiq_glue.h>
#endif

void kernel_kbox_write_text(char *text, size_t text_len, int is_newline)
{
	int kbox_reg_id = get_kbox_region();

	if (is_newline)
		text_len += 1;
	kern_kbox_write(kbox_reg_id, text, text_len);
}

#if (defined(CONFIG_RTOS_PPC_DYING_INT) || defined(CONFIG_FIQ_GLUE))

/* Define a per cpu log buffer for printk in fiq */
#define PRINTK_BUFFER_SIZE_FIQ	512

static DEFINE_PER_CPU(char[PRINTK_BUFFER_SIZE_FIQ], kbox_logbuf_in_fiq);

/*
 * the function is called in fiq, because the printk maybe solflockup in fiq
 * vprintk_emit:
 *               raw_spin_lock(&logbuf_lock)
 *               ...                         ------- here come the fiq
 *               raw_spin_unlock(&logbuf_lock)
 * in the fiq will call printk too.
 */
int printk_in_kbox(const char *fmt, va_list args)
{
	int text_len = 0;
	char *logbuf_in_fiq = NULL;
	const char *skip_header;

	logbuf_in_fiq = get_cpu_ptr(kbox_logbuf_in_fiq);
	text_len = vscnprintf(logbuf_in_fiq, PRINTK_BUFFER_SIZE_FIQ, fmt, args);

	skip_header = printk_skip_level(logbuf_in_fiq);
	/*
	 * No need to check length here because vscnprintf
	 * put '\0' at the end of the string.
	 */
	text_len -= skip_header - logbuf_in_fiq;
	kern_kbox_write(get_kbox_region(), skip_header, text_len);
	put_cpu_ptr(kbox_logbuf_in_fiq);

	return text_len;
}

bool being_fiq(void)
{
	bool ret = false;
#ifdef CONFIG_RTOS_PPC_DYING_INT
	if (unlikely(get_dying_mode() == true))
		return true;
#endif
#ifdef CONFIG_FIQ_GLUE
	ret = entry_fiq_mode;
#ifdef CONFIG_RTOS_HAL_FIQ_GLUE_EARLY
	ret &= (g_fiq_early_mode == EARLY_FIQ_UNREGISTER || g_fiq_early_mode == EARLY_FIQ_DISABLED);
#endif
#endif
	return ret;
}

#endif

